package imgsm

import (
	"image"
	"image/jpeg"
	"image/png"
	"os"
	"path/filepath"
	"strconv"
)

func width(i image.Image) int {
	return i.Bounds().Max.X - i.Bounds().Min.X
}

func height(i image.Image) int {
	return i.Bounds().Max.Y - i.Bounds().Min.Y
}

func splitPattern(img image.Image, splitCount int, direction string) [][]int {

	ret := make([][]int, 0)
	var d int
	if direction == "v" || direction == "V" {
		d = height(img)
		for i := 0; i < splitCount; i++ {
			x1 := 0
			x2 := width(img)
			offSet := d / splitCount
			y1 := offSet * i
			y2 := (i + 1) * offSet
			el := []int{x1, y1, x2, y2}
			ret = append(ret, el)
		}

	} else if direction == "h" || direction == "H" {
		d = width(img)
		for i := 0; i < splitCount; i++ {
			offSet := d / splitCount
			x1 := offSet * i
			y1 := 0
			x2 := (i + 1) * offSet
			y2 := height(img)
			el := []int{x1, y1, x2, y2}
			ret = append(ret, el)

		}
	}

	return ret
}

func Split(targetDir string, srcImgPath string, direction string, splitCount int, srcImgType, targetImgType string) error {

	srcFile, err := os.Open(srcImgPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()
	var srcImg image.Image
	if srcImgType == "jpg" {
		srcImg, err = jpeg.Decode(srcFile)

	} else {
		srcImg, err = png.Decode(srcFile)
	}
	if err != nil {
		return err
	}
	sp := splitPattern(srcImg, splitCount, direction)

	spLen := len(sp)
	var square image.Rectangle
	var targetImgPart image.Image
	var targetFilePath string
	var targetFile *os.File

	for i := 0; i < spLen; i++ {

		square = image.Rect(sp[i][0], sp[i][1], sp[i][2], sp[i][3])

		targetImgPart = srcImg.(interface {
			SubImage(r image.Rectangle) image.Image
		}).SubImage(square)
		targetFilePath = filepath.Join(targetDir, "split_"+strconv.Itoa(i)+"."+targetImgType)
		targetFile, err = os.Create(targetFilePath)
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if targetImgType == "png" {
			enc := png.Encoder{
				/*
					DefaultCompression CompressionLevel = 0
					NoCompression      CompressionLevel = -1
					BestSpeed          CompressionLevel = -2
					BestCompression    CompressionLevel = -3
				*/
				CompressionLevel: png.BestCompression,
			}
			err = enc.Encode(targetFile, targetImgPart)

		} else if targetImgType == "jpg" {
			err = jpeg.Encode(targetFile, targetImgPart, &jpeg.Options{Quality: 90})
		}

		if err != nil {

			return err
		}
	}

	return nil

}

func SplitTo9(srcImgPath string, srcImgType, targetImgType, targetDir string) error {
	srcFile, err := os.Open(srcImgPath)
	if err != nil {
		return err
	}
	defer srcFile.Close()
	var srcImg image.Image
	if srcImgType == "jpg" {
		srcImg, err = jpeg.Decode(srcFile)

	} else {
		srcImg, err = png.Decode(srcFile)
	}
	if err != nil {
		return err
	}

	sp := splitPatternForGrid9(srcImg)
	spLen := len(sp)
	var square image.Rectangle
	var targetImgPart image.Image
	var targetFilePath string
	var targetFile *os.File

	for i := 0; i < spLen; i++ {

		square = image.Rect(sp[i][0], sp[i][1], sp[i][2], sp[i][3])

		targetImgPart = srcImg.(interface {
			SubImage(r image.Rectangle) image.Image
		}).SubImage(square)
		targetFilePath = filepath.Join(targetDir, "split_"+strconv.Itoa(i)+"."+targetImgType)
		targetFile, err = os.Create(targetFilePath)
		if err != nil {
			return err
		}
		defer targetFile.Close()

		if targetImgType == "png" {
			enc := png.Encoder{
				/*
					DefaultCompression CompressionLevel = 0
					NoCompression      CompressionLevel = -1
					BestSpeed          CompressionLevel = -2
					BestCompression    CompressionLevel = -3
				*/
				CompressionLevel: png.BestCompression,
			}
			err = enc.Encode(targetFile, targetImgPart)

		} else if targetImgType == "jpg" {
			err = jpeg.Encode(targetFile, targetImgPart, &jpeg.Options{Quality: 90})
		}

		if err != nil {

			return err
		}
	}

	return nil

}

func splitPatternForGrid9(srcImg image.Image) [][]int {

	ret := make([][]int, 0)

	//if direction == "v" || direction == "V" {
	w := width(srcImg)
	h := height(srcImg)
	offSetR := h / 3
	offSetC := w / 3

	for r := 0; r < 3; r++ {
		//行偏移,仅应用在y
		for c := 0; c < 3; c++ {
			//行偏移,仅应用在x
			x1 := offSetC * c
			y1 := offSetR * r

			x2 := offSetC * (c + 1)
			y2 := (r + 1) * offSetR
			el := []int{x1, y1, x2, y2}
			ret = append(ret, el)
		}

	}

	return ret
}
